package com.zs.grain.ui

import android.app.Application
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbManager
import android.os.Bundle
import android.util.Log
import androidx.lifecycle.MutableLiveData
import javax.inject.Inject
import com.zs.grain.service.DataService
import com.xnkj1688.semplibrary.mvvm.BaseViewModel
import android.widget.Toast
import com.github.mjdev.libaums.UsbMassStorageDevice
import com.github.mjdev.libaums.fs.FileSystem
import com.github.mjdev.libaums.fs.UsbFile
import com.github.mjdev.libaums.fs.UsbFileStreamFactory
import com.jeremyliao.liveeventbus.LiveEventBus
import com.zs.grain.service.DeviceService
import com.zs.grain.service.SignalRService
import com.xnkj1688.semplibrary.entity.Advertisement
import io.reactivex.Single
import io.reactivex.schedulers.Schedulers
import java.io.File
import java.io.FileOutputStream

class AdvertisementViewModel @Inject constructor(
    val mApp: Application,
    val mDataService: DataService,
    val mDeviceService: DeviceService,
    val mSignalRService: SignalRService
) : BaseViewModel(mApp) {
    var id: Long = 0
    var name: String = "name"
    val advertisementViewModels = MutableLiveData<List<Advertisement>>()

    init {
    }

    fun init() {
        advertisementViewModels.value = mDataService.advertisements
    }

    fun onClickReboot() {
        LiveEventBus.get("Reboot").post(true)
    }

    fun onClickRead() {
        Single.just("")
            .observeOn(Schedulers.io())
            .subscribe({
                val result = this.readUsb("/zs_assets/ads/", mDataService.adsPath)
                if (result == null) return@subscribe

                val ads = mDataService.advertisements
                var adsPath = mDataService.adsPath
                val list = ArrayList<Advertisement>()
                for (item in result) {
                    item.fileName = item.fileName.replace(adsPath, "")
                    var ad = ads.find { x -> x.fileName == item.fileName }
                    if (ad == null) {
                        mDataService.DaoAdvertisement.insert(item)
                    } else if (ad.delete ?: false) {
                        File("$adsPath${item.fileName}").delete()
                        mDataService.DaoAdvertisement.delete(ad)
                    }
                }
                for (item in ads) {
                    var ad = result.find { x -> x.fileName == item.fileName }
                    if (ad == null && (item.enable ?: false))
                        mDataService.DaoAdvertisement.delete(item)
                }
                var advertisements = mDataService.advertisements.toTypedArray()
                if (advertisements != null && advertisements.size > 0) {
                    mSignalRService.uploadAdvertisements(advertisements)
                        .flatMap {
                            if (it) mSignalRService.advertisements
                            else throw Exception("广告列表上传云端失败")
                        }.subscribe({
                            mDataService.DaoAdvertisement.deleteAll()
                            mDataService.DaoAdvertisement.insertInTx(it.toList())
                            this.postToast("广告列表上传云端成功", Toast.LENGTH_SHORT)
                            Thread.sleep(1000)
                            this.uiNotify.postValue(this.getNotify("HideProgress"))
                        }, {
                            it.printStackTrace()
                            this.postToast("广告列表同步失败：" + it.message, Toast.LENGTH_LONG)
                            Thread.sleep(1000)
                            this.uiNotify.postValue(this.getNotify("HideProgress"))
                        })
                } else
                    this.uiNotify.postValue(this.getNotify("HideProgress"))
            }, {
                it.printStackTrace()
                this.postToast("广告更新失败:" + it.message, Toast.LENGTH_LONG)
                Thread.sleep(1000)
                this.uiNotify.postValue(this.getNotify("HideProgress"))
            })
    }

    fun onUsbAttached(context: Context, intent: Intent) {
        intent.getParcelableExtra<UsbDevice>(UsbManager.EXTRA_DEVICE)?.run {
            val usbManager = context.getSystemService(Context.USB_SERVICE) as UsbManager
            var storageDevices = UsbMassStorageDevice.getMassStorageDevices(context)
            for (device in storageDevices) {
                if (device.usbDevice.deviceId == this.deviceId) {
                    if (!usbManager.hasPermission(device.usbDevice)) {
                        Log.d(TAG, "requestPermission")
                        val pendingIntent = PendingIntent.getBroadcast(
                            context, 0,
                            Intent(ACTION_USB_PERMISSION), 0
                        )
                        usbManager.requestPermission(device.getUsbDevice(), pendingIntent)
                    }
                    break
                }
            }
        }
    }

    fun onUsbPermession(context: Context, intent: Intent) {
        intent.getParcelableExtra<UsbDevice>(UsbManager.EXTRA_DEVICE)?.run {
            //            val path = intent.getStringExtra("Path")
            val usbManager = context.getSystemService(Context.USB_SERVICE) as UsbManager
            var storageDevices = UsbMassStorageDevice.getMassStorageDevices(context)
            for (device in storageDevices) {
                if (device.usbDevice.deviceId == this.deviceId) {
                    if (usbManager.hasPermission(device.usbDevice)) {
//                        readDevice(device, "zs_assets")
                    }
                    break
                }
            }
        }
    }

    fun readUsb(srcPath: String, dstPath: String): MutableList<Advertisement>? {
        var result = ArrayList<Advertisement>()
        var storageDevices = UsbMassStorageDevice.getMassStorageDevices(mApp)
        val usbManager = mApp.getSystemService(Context.USB_SERVICE) as UsbManager
        for (device in storageDevices) {
            if (usbManager.hasPermission(device.usbDevice)) {
                var list = readDevice(device, srcPath, dstPath)
                result.addAll(list)
            } else {
                val intent = Intent(ACTION_USB_PERMISSION).apply { this.putExtra("Path", srcPath) }
                val pendingIntent =
                    PendingIntent.getBroadcast(mApp, 0, intent, 0)
                usbManager.requestPermission(device.getUsbDevice(), pendingIntent)
                return null
            }
        }
        return result
    }

    @Synchronized
    private fun readDevice(
        device: UsbMassStorageDevice,
        srcPath: String,
        dstPath: String
    ): MutableList<Advertisement> {
        this.uiNotify.postValue(this.getNotify("ShowProgress"))
        Thread.sleep(100)
        var result = ArrayList<Advertisement>()
        device.init();
        val currentFs = device.getPartitions().get(0).getFileSystem()
        val root = currentFs.rootDirectory
        var files = root.listFiles()
        var file: UsbFile? = null
        while (file == null && files != null && files.size > 0) {
            for (item in files) {
                Log.d(TAG, item.absolutePath)
                if (item.isDirectory() && srcPath.startsWith(item.absolutePath + "/", true)) {
                    if (srcPath == item.absolutePath + "/") file = item
                    else files = item.listFiles()
                    break;
                }
            }
        }
        if (file != null) {
            var list = readFolder(currentFs, file, dstPath);
            result.addAll(list)
//                this.deleteAd(file)
        }
        return result
    }

    private fun readFolder(currentFs: FileSystem, file: UsbFile, targetDir: String)
            : MutableList<Advertisement> {
        var result = ArrayList<Advertisement>()
        for (item in file.listFiles()) {
            Log.d(TAG, item.absolutePath + "--" + targetDir)
            if (item.isDirectory) {
                var dir = File("$targetDir${item.name}/")
                if (!dir.exists()) dir.mkdir()
                var list = readFolder(currentFs, item, dir.absolutePath)
                result.addAll(list)
                continue
            }
            var ad = Advertisement().apply { fileName = "$targetDir${item.name}" }
            result.add(ad)
            val source = UsbFileStreamFactory.createBufferedInputStream(item, currentFs);
            var targetFile = File(ad.fileName)
            if (targetFile.exists()) continue
            val target = FileOutputStream(targetFile)
            Log.d(TAG, item.absolutePath + "--" + targetFile.absoluteFile)

            val buf = ByteArray(10 * 1024)
            var size = source.read(buf, 0, 10240)
            while (size > 0) {
                target.write(buf, 0, size)
                size = source.read(buf, 0, 10240)
            }
            source.close()
            target.close()
        }
        return result
    }

    private fun deleteAd(file: UsbFile) {
        var adsDir = File(mDataService.adsPath);
        var usbDir: UsbFile? = null
        for (item in file.listFiles()) {
            if (item.name == adsDir.name) {
                usbDir = item;
                break;
            }
        }
        if (usbDir == null) return;
        var usbfiles = usbDir.list()
        for (item in adsDir.list()) {
            if (usbfiles.indexOf(item) < 0) {
                var f = File("$adsDir/$item");
                f.delete()
            }
        }
    }

    fun onClickVideo(vm: Advertisement) {
        if (!(vm.enable ?: true)) return

        var bundle = Bundle()
        bundle.putString("UI", "VideoShow")
        bundle.putLong("VideoId", vm.id)
        LiveEventBus.get("VideoShow").post(bundle)
    }

    companion object {
        val TAG = "AdvertisementViewModel"
        val ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"
    }
}